/*
* MM32L052NT:可用IO 27个 PA0-PA15 PB0-PB8, PD0,PD1
* GPIOA 起始地址：0x4800_0000 - 0x4800_03ff
* GPIOB 起始地址：0x4800_0400 - 0x4800_07ff
* GPIOD 起始地址：0x4800_0C00 - 0x4800_0fff
* MM32L073 有：
* GPIOC 起始地址：0x4800_0800 - 0x4800_0bff
*/

//GPIO 寄存器结构
struct gpio {
	volatile unsigned long cr[2];  //端口配置寄存器，高32bit+低32bit
	volatile unsigned long idr;     //15个端口输入寄存器，只读
	volatile unsigned long odr;     //15个端口输出寄存器，可读写
	volatile unsigned long bsrr;    //置位和清零寄存器，写1，操作
	volatile unsigned long brr;     //端口位清除，只写
	volatile unsigned long lock;    //端口锁定
	volatile unsigned long res;    	//保留
	volatile unsigned long afrl;    //多功能端口配置
	volatile unsigned long afrh;    //多功能端口配置
};

#define GPIOA_BASE	(struct gpio *) 0x40000000
#define GPIOB_BASE	(struct gpio *) 0x40000400
#define GPIOC_BASE	(struct gpio *) 0x40000800
#define GPIOD_BASE	(struct gpio *) 0x40000c00



/* 每个GPIO组有16bit
 * cr寄存器配置每个端口，每个bit需要4位配置，共需要14×4bit
 * cr[0] 配置bit0-7
 * cr[1] 配置bit8-15
 *
 * 4个bit分成2部分 ：
 * bit0 ： 0：输入(复位默认) 1:输出
 * bit1 ： 保留
 * bit2:bit3:
 *   当为输入时候 2'b00:模拟输入 2'b01:浮空输入 2'b10:上下拉 2'b11:保留
 *   当为输出时候 2'b00:推挽输出 2'b01:开漏输出 2'b10:复用推挽输出 2'b11:复用开漏输出
 * 
 */

//三种输入 模拟输入模式 浮空输入 上下拉输入
#define INPUT_ANALOG	0x0
#define INPUT_FLOAT		0x4
#define INPUT_PUPD		0x8

//4种输出 MM32L052 没有ST速度等级,因为bit1被保留
#define OUTPUT_PP 		0x0
#define OUTPUT_OD	 	0x4
#define OUTPUT_ALT_PP	0x8
#define OUTPUT_ALT_OD	0xc

//GPIO 只能配输入和输出，没有速度等级
#define GPIO_IN			0x0
#define GPIO_OUT		0x1

struct gpio *led_gp;
unsigned long on_mask;
unsigned long off_mask;

static void gpio_mode ( struct gpio *gp, int bit, int mode )
{
	int reg;
	int conf;
	int shift;

	reg = bit / 8;
	shift = (bit%8) * 4;

	conf = gp->cr[reg] & ~(0xf<<shift);
	gp->cr[reg] = conf | (mode << shift);
}

void gpio_a_set ( int bit, int val )
{
	struct gpio *gp = GPIOA_BASE;

	if ( val )
	    gp->bsrr = 1 << bit;
	else
	    gp->bsrr = 1 << (bit+16);
}

void gpio_b_set ( int bit, int val )
{
	struct gpio *gp = GPIOB_BASE;

	if ( val )
	    gp->bsrr = 1 << bit;
	else
	    gp->bsrr = 1 << (bit+16);
}

void gpio_c_set ( int bit, int val )
{
	struct gpio *gp = GPIOC_BASE;

	if ( val )
	    gp->bsrr = 1 << bit;
	else
	    gp->bsrr = 1 << (bit+16);
}

void gpio_a_output ( int bit )
{
	gpio_mode ( GPIOA_BASE, bit, GPIO_OUT | OUTPUT_PP );
}

void gpio_b_output ( int bit )
{
	gpio_mode ( GPIOB_BASE, bit, GPIO_OUT | OUTPUT_PP );
}

void gpio_c_output ( int bit )
{
	gpio_mode ( GPIOC_BASE, bit, GPIO_OUT | OUTPUT_PP );
}

void gpio_a_input ( int bit )
{
	gpio_mode ( GPIOA_BASE, bit, INPUT_FLOAT );
}

void gpio_b_input ( int bit )
{
	gpio_mode ( GPIOB_BASE, bit, INPUT_FLOAT );
}

void gpio_c_input ( int bit )
{
	gpio_mode ( GPIOC_BASE, bit, INPUT_FLOAT );
}


void led_init ( int bit )
{
	gpio_mode ( GPIOC_BASE, bit, GPIO_OUT | OUTPUT_OD );

	led_gp = GPIOC_BASE;
	off_mask = 1 << bit;
	on_mask = 1 << (bit+16);
}

void led_on ( void )
{
	led_gp->bsrr = on_mask;
}

void led_off ( void )
{
	led_gp->bsrr = off_mask;
}

//MM32 052nt PA2,PA3 配置为uart2
void gpio_uart2 ( void )
{
	gpio_mode ( GPIOA_BASE, 2, GPIO_OUT | OUTPUT_ALT_PP);
	// gpio_mode ( GPIOA_BASE, 3, INPUT_FLOAT );
}

//MM32 052nt uart1可选:
// PA9:tx PA10:rx PA9:rx PA10:tx
// PB6:tx PB7:rx
void gpio_uart1 ( void )
{
	gpio_mode ( GPIOA_BASE, 9, GPIO_OUT | OUTPUT_ALT_PP );
	// gpio_mode ( GPIOA_BASE, 10, INPUT_FLOAT );
}



#if 0

/* XXX - this is one special case, we have 16 to consider */
/* Timer 2, pin 1 is A15 of 0-15 */
void
gpio_timer ( void )
{
	/* Timer 2, outputs  1,2,3,4 */
	gpio_mode ( GPIOA_BASE, 15, OUTPUT_50M | ALT_PUSH_PULL );
	gpio_mode ( GPIOA_BASE, 1, OUTPUT_50M | ALT_PUSH_PULL );
	gpio_mode ( GPIOA_BASE, 2, OUTPUT_50M | ALT_PUSH_PULL );
	gpio_mode ( GPIOA_BASE, 3, OUTPUT_50M | ALT_PUSH_PULL );
}
#endif
/* THE END */
